#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <memory>

///////////////////////////////////////////
/// 线程安全的队列
///
template<class T>
class Buffer
{
private:
    mutable std::mutex mut;
    std::queue<T> data_queue;
    std::condition_variable data_con;
    int max_size_;

public:
    //默认max_size = 0 此时没有size的限制，buffer理论上可以无限扩大
    Buffer(int max_size = 0){
        max_size_ = max_size;
    }
    //复制构造函数，用于将其他的队列数据进行拷贝
    Buffer(Buffer const& other, int max_size = 0)
    {
        max_size_ = max_size;
        //lock_guard在构造的时候传入一个mutex并lock,在析构的时候自动unlock。
        std::lock_guard<std::mutex> lk(other.mut);
        data_queue = other.data_queue;
        while((max_size_ != 0) && (data_queue.size() > max_size_))
            data_queue.pop();
    }
    //向buffer中放入一个值
    void push(T tValue)
    {
        std::lock_guard<std::mutex> lk(mut);
        data_queue.push(tValue);
        //如果buffer大小超出了预定，则弹出一个值
        if((max_size_ != 0) && (data_queue.size() > max_size_))
            data_queue.pop();
        //通知condition_varibl  buffer发生了改变（有新的数据）
        data_con.notify_one();
    }

    //等待式样的数据获取，如果当前没有数据就一直等待
    void wait_and_pop(T& tValue)
    {
        std::unique_lock<std::mutex> lk(mut);
        //等待直到condition_varible被notify 且 data_queue不为empty
        //这里用了一个lambda表达式做捕获，具体用法可以参考
        //http://www.cnblogs.com/zhuyp1015/archive/2012/04/08/2438176.html
        data_con.wait(lk,[this]{return !data_queue.empty();});
        tValue = data_queue.front();
        data_queue.pop();
    }

    //带超时机制的数据获取，如果等待超过一段时间，则退出返回false
    bool wait_and_pop_for_ms(T& tValue, int microseconds = 10)
    {
        std::unique_lock<std::mutex> lk(mut);
        if(data_con.wait_for(lk, std::chrono::microseconds(microseconds),
                             [this]{return !data_queue.empty();})){
            tValue = data_queue.front();
            data_queue.pop();
            return true;
        }
        else{
            tValue = T();
            return false;
        }
    }

    //以共享内存形式等待并返回
    std::shared_ptr<T>wait_and_pop()
    {
        std::unique_lock<std::mutex> lk(mut);
        data_con.wait(lk,[this]{return !data_queue.empty();});
        std::shared_ptr<T> ret (std::make_shared<T>(data_queue.front()));
        data_queue.pop();
        return ret;
    }

    //尝试获取元素，如果当前队列为空，则返回，反之等待
    //和wait_and_pop的区别在于是否等待空的数据队列
    bool try_pop(T& tValue)
    {
        std::lock_guard<std::mutex> lk(mut);
        if(data_queue.empty())
            return false;
        tValue = data_queue.front();
        data_queue.pop();
        return true;
    }

    std::shared_ptr<T> try_pop()
    {
        std::lock_guard<std::mutex> lk(mut);
        if(data_queue.empty())
            return std::shared_ptr<T>();
        std::shared_ptr<T> ret(std::make_shared(data_queue.front()));
        data_queue.pop();
        return ret;
    }

    // 检查当前数据是否为空
    bool empty() const
    {
        std::lock_guard<std::mutex> lk(mut);
        return data_queue.empty();
    }
};

//封装的线程类
class Thread{
public:
    Thread();
    virtual ~Thread(){}
    //子类需要复写的线程主体，该主体会一直循环
    virtual void main_loop_impl() = 0;
    //线程主体入口，主要用于控制循环
    bool main_loop();
    //线程开始方法
    bool start();
    //线程停止方法
    bool stop();
    //共享内存区域
    bool set_buffer(Buffer<int>* _buffer);
    //设置循环率
    bool set_period(int _period);

protected:
    Buffer<int>* buffer_;
    int period_;

private:
    bool stop_;
    std::thread* thread_;
};

Thread::Thread(){
    stop_ = false;
    buffer_ = nullptr;
    thread_ = nullptr;
    period_ = 100;
}

bool Thread::set_period(int _period){
    period_ = _period;
    return true;
}

bool Thread::start(){
    if(thread_ == nullptr){
        //利用类内函数fork新线程
        thread_ = new std::thread(std::mem_fn(&Thread::main_loop), this);
        thread_->detach();
    }
    return true;
}

//主循环，在stop_为false的时候会一直执行
bool Thread::main_loop(){
    while(!stop_){
        main_loop_impl();
        std::this_thread::sleep_for(std::chrono::milliseconds(period_));
    }
    return true;
}

bool Thread::stop(){
    stop_ = true;
    return true;
}

bool Thread::set_buffer(Buffer<int> *_buffer){
    buffer_ = _buffer;
    return true;
}

class Productor : public Thread{
public:
    void main_loop_impl();
};

//生产者向buffer中不断压入数字
void Productor::main_loop_impl(){
    static int counter = 0;
    buffer_->push(counter++);
}

class Consumer : public Thread{
public:
    void main_loop_impl();
};

void Consumer::main_loop_impl(){
    int value;
    if(buffer_->try_pop(value))
        std::cout << "get value ::  " << value << std::endl;
    else
        std:: cout << "no value" << std::endl;
}

int main(){
    Buffer<int> buffer;
    Productor productor;
    Consumer consumer_1;
    Consumer consumer_2;

    //生产者以50ms的周期发布新数据
    productor.set_period(50);
    //两个消费者分别以80和70ms的速度进行消费
    //我们特地设置这样一个场景，用于说明在处理程序的处理时间无法满足图片生成速率的情况下如何进行处理
    consumer_1.set_period(80);
    consumer_2.set_period(70);

    productor.set_buffer(&buffer);
    consumer_1.set_buffer(&buffer);
    consumer_2.set_buffer(&buffer);

    productor.start();
    consumer_1.start();
    consumer_2.start();

    for(int i = 1; i < 10; i++){
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    //暂停了生产者和一个消费者
    productor.stop();
    consumer_1.stop();

    for(int i = 1; i < 10; i++){
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    return 0;
}
